package com.hundsun.cprs.yyt.service.match.core.command;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hundsun.cprs.yyt.service.match.core.Matching;
import com.hundsun.cprs.yyt.service.match.core.queue.EntrustQueue;
import com.hundsun.cprs.yyt.service.match.core.queue.PriceCell;
import com.hundsun.cprs.yyt.service.match.domain.DefaultTradeMatch;
import com.hundsun.cprs.yyt.service.match.domain.TradeEntrust;
import com.hundsun.cprs.yyt.service.match.domain.TradeMatchDetail;
import com.hundsun.cprs.yyt.service.match.service.ServiceLocate;
import com.hundsun.cprs.yyt.util.TradeEntrustBeanUtil;

/**
 * 挂买单委托数量按新会员的占比切分匹配
 */
public class AmountSplitBaseCommand extends BaseCommand implements MatchingCommand {
    private static final Log logger = LogFactory.getLog(AmountSplitBaseCommand.class);

    protected TradeEntrust entrust;

    public AmountSplitBaseCommand(TradeEntrust entrust) {
        super();
        this.entrust = entrust;
    }
    
    protected long matchPerform(Matching matching,DefaultTradeMatch match,List<TradeEntrust> expireEntrust,long amount,PriceCell... priceCells){
        long suitedAmount = 0L;// 匹配成功的数量
        if (priceCells == null) {
            return suitedAmount;
        }
        PriceCell matchPriceCell = priceCells[0];
        //如果价格队列只有1个则不需要切换
        boolean isSwitch = priceCells.length > 1 ? false:true;
        long matchAmount = amount;
        while (true && matchPriceCell != null) {
            TradeEntrust bestEntrust = checkAndReturnBestEntrust(matchPriceCell.getEntrustQueue(),expireEntrust);
            if (bestEntrust == null) {
                if (!isSwitch) {
                    matchPriceCell = priceCells[1];
                    isSwitch = true;
                    continue;
                } else {
                    matchPriceCell = null;
                    logger.debug("2没有可匹配的" + (entrust.isBuy()?"挂卖单":"挂买单"));
                    break;
                }
            }
            
            //定价,以买家订单价格优先成交
            long bestPrice = entrust.isBuy() ? entrust.getEntrustPrice() : bestEntrust.getEntrustPrice();
            // 找到和价格对应的买(卖)单
            long bestEntrustAmount = bestEntrust.getSurplusEntrustAmount();
            if (matchAmount <= bestEntrustAmount) {// 订单全部成交,匹配结束
                entrust.subEntrustAmount(matchAmount);
                bestEntrust.subEntrustAmount(matchAmount);// 大家都扣掉成交的量
                int matchTransationCount = match.getTransactionCountSeq();
                match.addMatchDetail(new TradeMatchDetail(entrust, matchAmount, bestPrice, false,matchTransationCount));
                match.addMatchDetail(new TradeMatchDetail(bestEntrust, matchAmount, bestPrice, true,matchTransationCount));
                if (entrust.isBuy()) {
                    matching.getQuotes().reduceSellingAmount(bestEntrust.getFundAccount(), matchAmount);
                } else {
                    matching.getQuotes().reduceBuyingAmount(bestEntrust.getFundAccount(), matchAmount);
                }
                suitedAmount += matchAmount;
                if (bestEntrust.isEntrustAmountAllMatch()) {
                    if (entrust.isBuy()) {
                        matching.getSellQueue().removeEntrust(bestEntrust);
                    } else {
                        matching.getBuyQueue().removeEntrust(bestEntrust);
                    }
                }
                break;
            } else {// 订单还有剩余,继续匹配
                matchAmount = matchAmount - bestEntrustAmount;
                entrust.subEntrustAmount(bestEntrustAmount);
                bestEntrust.subEntrustAmount(bestEntrustAmount);// 大家都扣掉成交的量
                int matchTransationCount = match.getTransactionCountSeq();
                match.addMatchDetail(new TradeMatchDetail(entrust, bestEntrustAmount, bestPrice, false,matchTransationCount));
                match.addMatchDetail(new TradeMatchDetail(bestEntrust, bestEntrustAmount, bestPrice, true,matchTransationCount));
                if (entrust.isBuy()) {
                    matching.getQuotes().reduceSellingAmount(bestEntrust.getFundAccount(), bestEntrustAmount);
                } else {
                    matching.getQuotes().reduceBuyingAmount(bestEntrust.getFundAccount(), bestEntrustAmount);
                }
                
                suitedAmount += bestEntrustAmount;
                if (entrust.isBuy()) {
                    matching.getSellQueue().removeEntrust(bestEntrust);
                } else {
                    matching.getBuyQueue().removeEntrust(bestEntrust);
                }
            }
        }
        return suitedAmount;
    }
    
    @Override
    public void perform(Matching matching, Executor executor){
        final DefaultTradeMatch match = new DefaultTradeMatch(matching.getTradeCenter().getStockCode());
        final List<TradeEntrust> expireEntrust = new ArrayList<TradeEntrust>();
        //针对买单,商品数按比例切分两份，一份匹配新用户委售单，一份匹配老用户委售单,若任何一份匹配不完全，则匹配反向委售单补齐
        long suitedAmount = 0L;// 匹配成功的数量
        long amount = entrust.getSurplusEntrustAmount();
        if (entrust.isBuy()) {
            //委买 需要切分商品数
            int matchBuyNewUserRate = matching.getTradeCenter().getMatchBuyNewUserRate();
            long newUserAmount = new BigDecimal(amount).multiply(new BigDecimal(matchBuyNewUserRate).movePointLeft(2)).setScale(0, BigDecimal.ROUND_UP).longValue();
            long oldUserAmount = amount - newUserAmount;
            
            if (logger.isDebugEnabled()) {
                logger.debug(MessageFormat.format("委买单[{0}]按{1}%切分匹配数:总{2},新{3},老{4}", entrust.getEntrustNO(),matchBuyNewUserRate,amount,newUserAmount,oldUserAmount));
            }
            
            PriceCell newUserPriceCell = matching.getSellQueue().getNewUserQueue().getHeader();
            PriceCell oldUserPriceCell = matching.getSellQueue().getOldUserQueue().getHeader();
            
            if (newUserAmount > 0) {
                if (newUserPriceCell != null) {
                    suitedAmount += matchPerform(matching, match, expireEntrust, newUserAmount, newUserPriceCell, oldUserPriceCell);
                } else {
                    suitedAmount += matchPerform(matching, match, expireEntrust, newUserAmount, oldUserPriceCell);
                }
            }
            
            if (oldUserAmount > 0) {
                if (oldUserPriceCell != null) {
                    suitedAmount += matchPerform(matching, match, expireEntrust, oldUserAmount, oldUserPriceCell, newUserPriceCell);
                } else {
                    suitedAmount += matchPerform(matching, match, expireEntrust, oldUserAmount, newUserPriceCell);
                }
            }
        } else {
            //委卖
            suitedAmount += matchPerform(matching, match, expireEntrust,amount,matching.getBuyQueue().getHeader());
        }

        if (logger.isDebugEnabled()) {
            logger.debug("match suited amount:" + suitedAmount);
        }

        final boolean historyHaveSuite = entrust.getEntrustAmount() > amount;//历史成交，即发生过撤回重新上报
        final boolean haveSuite = suitedAmount > 0;

        if (haveSuite) {// 下单有成交
            match.calculate();
        }

        // 还有剩下的
        if (!entrust.isEntrustAmountAllMatch()) {
            if (entrust.isLastEntrustPaste()) {
                // 剩下的挂单
                if (haveSuite || historyHaveSuite) {
                    // 改成部成
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusPartDealt);
                } else {
                    // 挂单状态
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusCommited);
                }
                if (entrust.isBuy()) {
                    matching.getBuyQueue().placeEntrust(entrust);
                    matching.getQuotes().addBuyingAmount(entrust.getFundAccount(),entrust.getSurplusEntrustAmount());
                } else {
                    matching.getSellQueue().placeEntrust(entrust);
                    matching.getQuotes().addSellingAmount(entrust.getFundAccount(),entrust.getSurplusEntrustAmount());
                }
            } else {
                // 剩下的撤销
                if (haveSuite) {
                    // 状态改为部撤
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusPartCanceled);
                } else {
                    // 改为已撤
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusCanceled);
                }
            }
        }
        
        if (!expireEntrust.isEmpty()) {
            //过期移除的订单，减少统计
            for(TradeEntrust entrust : expireEntrust){
                if (entrust.isBuy()) {
                    matching.getQuotes().reduceBuyingAmount(entrust.getFundAccount(), entrust.getSurplusEntrustAmount());
                } else {
                    matching.getQuotes().reduceSellingAmount(entrust.getFundAccount(), entrust.getSurplusEntrustAmount());
                }
            }
        }

        //匹配成交后异步处理
        executor.execute(new Runnable() {
            public void run() {
                if (haveSuite) {
                    // 保存交易数据
                    ServiceLocate.getTradeMatchService().updateAfterMatch(TradeEntrustBeanUtil.copyPropertiesFrom(match));
                }
                if (!expireEntrust.isEmpty()) {
                    if (logger.isInfoEnabled()) {
                        logger.info("有过期订单，更新订单为已撤销" + expireEntrust.size());
                    }
                    ServiceLocate.getTradeMatchService().cancelEntrust(TradeEntrustBeanUtil.copyPropertiesFrom(expireEntrust));
                }
            }
        });
    }
    
    private TradeEntrust checkAndReturnBestEntrust(EntrustQueue queue,List<TradeEntrust> expireEntrust){
        while(true){
            TradeEntrust bestEntrust = queue.getHeader();
            
            //未过期的订单返回
            if (bestEntrust != null && 
                bestEntrust.getExpireDate() != null && 
                System.currentTimeMillis() > bestEntrust.getExpireDate().getTime()) {
                
                queue.removeEntrust(bestEntrust);
                long entrustAmount = bestEntrust.getEntrustAmount();
                long surplusEntrustAmount = bestEntrust.getSurplusEntrustAmount();
                if (entrustAmount > surplusEntrustAmount) {
                    bestEntrust.setEntrustStatus(TradeEntrust.EntrustStatusPartCanceled);
                } else {
                    bestEntrust.setEntrustStatus(TradeEntrust.EntrustStatusCanceled);
                }
                expireEntrust.add(bestEntrust);
                continue;
            }
            return bestEntrust;
        }
    }
}
